#!/bin/sh
# Bug reports and comments to Igor.Ermolaev@intel.com
sfx=${2:-NI}
source $(dirname $(readlink -f ${BASH_SOURCE[0]:-$0}))/find_loop
anchor=${3:-loop.$anchor_isa.s}
module=`$base/addrs2 base "$1"`

global="$TRACING_SDK_SDE_MPI_ARGS"
log_type=${TRACING_SDK_LOG_TYPE:-pinball}
prior=${TRACING_SDK_PROPAGATE_EXTRA//B/000000000};prior=${prior//M/000000};prior=${prior//K/000}
precond="$TRACING_SDK_PROPAGATE_CND"
action=-pinlit2

if [ "${anchor##*.}" == tbz2 ];then
   line=`tar xfjO $anchor --occurrence=1 --wildcards 'loop.*.s' 2>/dev/null|head -n 1|sed 's/;\s*\(\/\)\?\([^\/]\+\/\)*//'`
   if [ -z "$line" ];then
      line=`tar xfjO $anchor --occurrence=1 --wildcards 'call.*.s' 2>/dev/null|head -n 1|sed 's/;\s*\(\/\)\?\([^\/]\+\/\)*//'`
      if [ -n "$line" ];then 
         selmsk='call.*.s'
         filter=get_call
         selrng='-s'
      fi
   else
      selmsk='loop.*.s'
      filter=get_loop
      selrng='-r'
   fi
   if [ -n "$line" ];then
      func=`tar xfjO $anchor --occurrence=1 --wildcards "$selmsk"|grep -P ';---\s+.+'|sed 's/;---\s\+\([^: ]\+\).*/\1/'`
   else
      path=`tar xfjO $anchor --occurrence=1 --wildcards 'path.*.s' 2>/dev/null|head -n 1|sed -n 's/^;\s\+dependencies:\s\+\(.\+\)/\1/p'`
      if [ -n "$path" ];then
         selmsk='path.*.s'
         func=''
         sel_rng='-r'
         tar xfj $anchor --occurrence=1 $path
      else
         selmsk='func.*.s'
         func=`tar xfjO $anchor --occurrence=1 --wildcards "$selmsk"|awk 'END{print $2}'`
         selrng="$func"
      fi
   fi
   if [ -z "$precond" ] && [ -z "$path" ];then
      precond=`tar tfj $anchor --occurrence=1 --wildcards 'precond.*.tbz2' 2>/dev/null`
      [ -n "$precond" ] && tar xfj $anchor --occurrence=1 $precond
   fi
else
   line=`head -n 1 $anchor|sed -n 's/;\s*\(\/\)\?\([^\/]\+\/\)*//p'`
   if [ -n "$line" ] && [ `echo "$line"|awk '{print $1}'` == 'dependencies:' ];then unset line; fi
   cmdl=`tail -n 1 $anchor|grep '; '`
   eval sde_args=( `echo $cmdl|sed 's/\s\+--\s\+\$@$//'|sed -n 's/^;\s\+sde\s\+\(.*\s\+-start-address\s\+\)\(0x[0-9a-fA-F]\+\)\(:[0-9]\+\)\?\(.*\s\+-stop-address\s\+\)\(0x[0-9a-fA-F]\+\)\(:[0-9]\+\)\?\(.*\s\+-length\s\+\)\([0-9]\+\)\(\s\+.*\)$/'"'"'\1'"' '"'\2'"' '"'\3'"' '"'\4'"' '"'\5'"' '"'\6'"' '"'\7'"' '"'\8'"' '"'\9'"'"'/p'` )
   if [ -n "$line" ];then
      if [[ "$anchor" == loop.*.s ]];then
         selmsk='loop.*.s'
         filter=get_loop
         selrng='-r'
      else
         selmsk='call.*.s'
         filter=get_call
         selrng='-s'
      fi
      func=`grep -P ';---\s+.+' $anchor|sed 's/;---\s\+\([^: ]\+\).*/\1/'`
   else
      if [[ "$anchor" == path.*.s ]];then
         selmsk='path.*.s'
         func=''
         sel_rng='-r'
         path=`sed -n 's/^;\s\+dependencies:\s\+\(.\+\)/\1/p' "$anchor"|head -n 1`
      else
         selmsk='func.*.s'
         if [ -z "${sde_args[0]}" ];then
            func=`echo $cmdl|awk '{print $2}'`
         else
            func=`tail -n 2 $anchor|awk 'NR==1{print $2}'`
         fi
         selrng="$func"
      fi
   fi
   if [ -z "${sde_args[0]}" ];then unset cmdl; fi
fi
org_func="$func"
for mf in "${match_funcs[@]}";do
   tgt_func=`echo "$func"|sed "$mf"`
   if [ "$tgt_func" != "$func" ];then
      func="$tgt_func"
      break
   fi
done
if [ -n "$TRACING_SDK_PROPAGATE_FUNC" ];then
   if [ -n "$line" ];then
      func=${TRACING_SDK_PROPAGATE_FUNC%%:*}
   else
      if [ "${TRACING_SDK_PROPAGATE_FUNC%%:[0-9]*}" == "$TRACING_SDK_PROPAGATE_FUNC" ];then func=${func#*:}; else func=''; fi
      func="$TRACING_SDK_PROPAGATE_FUNC${func:+:$func}"
   fi
fi
if [ -n "$precond" ] && [ -z "$TRACING_SDK_PROPAGATE_CND" ];then
   $base/precond propagate "$module" $isa $precond
   precond=precond.$isa.tbz2
fi

shown_luqi=false
iters_rqrd=false

if [ -n "$line" ];then
   if [ -n "$TRACING_SDK_PROPAGATE_SRCF" ];then line=`echo $line|sed 's|^[^:]\+|'"$TRACING_SDK_PROPAGATE_SRCF"'|'`; fi
   if [ -n "$TRACING_SDK_PROPAGATE_SRCN" ];then line=`echo $line|sed 's|^\([^:]\+\):[0-9]\+|\1:'"$TRACING_SDK_PROPAGATE_SRCN"'|'`; fi
   if [ -n "$TRACING_SDK_PROPAGATE_SRCL" ];then line=`echo $line|sed 's|^\S\+|'"$TRACING_SDK_PROPAGATE_SRCL"'|'`; fi
   if [ -n "$TRACING_SDK_PROPAGATE_HIDX" ];then
      ti=${TRACING_SDK_PROPAGATE_HIDX:0:1}
      if [ "$ti" == v ] || [ "$ti" == i ];then
         line=`echo $line|sed 's/-[iv]\s\+[0-9]\+\|$/ -'"$ti"' '"${TRACING_SDK_PROPAGATE_HIDX:1}"'/'`
      else
         line=`echo $line|sed 's/\(-[iv]\)\s\+[0-9]\+/\1 '"$TRACING_SDK_PROPAGATE_HIDX"'/'`
      fi
   fi
   if [ "$TRACING_SDK_PROPAGATE_VFCT" == full ];then
      nst_ofs=-1
   elif [ "$TRACING_SDK_PROPAGATE_VFCT" == conflict ];then
      nst_ofs=+1
   elif [ -n "$TRACING_SDK_PROPAGATE_NST" ];then
      nst_ofs=$TRACING_SDK_PROPAGATE_NST
   else 
      nst_ofs=0
   fi
   if [ $nst_ofs != 0 ];then
      nst=`echo $line|sed -n 's/^.\+\s-n\s\+\([0-9]\+\)\s\?.*$/\1/p'`
      if [ -n "$nst" ];then
         nst=`echo "$nst+(0$nst_ofs)"|bc`
         if [ $nst == -1 ];then nst=0;iters_rqrd=true; fi
         line=`echo $line|sed 's/\(\s-n\s\+\)[0-9]\+/\1'$nst'/'`
      fi
   fi
   if [ -n "$TRACING_SDK_PROPAGATE_FUNC" ] && [ $func != $TRACING_SDK_PROPAGATE_FUNC ];then
      line=`echo $line|sed 's/\s-r\s\+\S\+\|$/ -r '$TRACING_SDK_PROPAGATE_FUNC'/'`
   elif [ $func != $org_func ];then
      line=`echo $line|sed 's/\(\s-r\s\)[^:]\+\(:\|$\)/\1'$func'\2/'`
   fi
   target=${selmsk/.\*./.$isa.}
   $base/get_disasm "$module"${func:+ $func} `echo $line|sed -n 's/^\s*;\s*\([^:]\+\:[0-9]\+\)\s.*$/\1/p'`|$base/$filter $line >$target
   var=$(grep -c ';===' $target)
   if [ "${anchor##*.}" == tbz2 ];then
      bloat=`tar xfjO $anchor --occurrence=1 --wildcards "$selmsk"|$base/find_lines|wc -l`
   else
      bloat=`$base/find_lines <$anchor|wc -l`
   fi
   bloat=`echo "scale=0;$bloat*(${TRACING_SDK_PROPAGATE_LUQI:-5})/1"|bc`
   if [ $var -eq 1 ] && [ `$base/find_lines <$target|wc -l` -gt $bloat ] && [ $bloat -ne 0 ];then
      echo
      echo Warning: Found loop will be ignored due to significant
      echo '         'increase of unique lines. To override, use
      echo '         'TRACING_SDK_PROPAGATE_LUQI=ratio
      echo
      shown_luqi=true
      var=0
   fi
elif [ -n "$func" ];then
   target=func.$isa.s
   $base/get_disasm "$module" ${func%%:[0-9]*} >$target
   echo >>$target;echo "; $func" >>$target
   var=1
elif [ -n "$path" ];then
   target=path.$isa.s
   $base/precond propagate "$module" $isa $path
   TRACING_SDK_ANCHOR_ISA=$isa $base/find_path >/dev/null
   precond=precond.$isa.tbz2
   if [ ! -r "$precond" ];then unset precond; fi
   var=1
else
   echo;echo Error: Neither 'loop.*.s' nor 'func.*.s' nor 'call.*.s' nor 'path.*.s' found in $anchor;echo;exit
fi
if [ $var -ne 1 ];then
   echo
   echo Warning: For specified loop more than one or none versions
   echo '         'were found. Trying to find close enough...
   echo
   inner=`echo $line|sed 's/\(^.\+\:[0-9]\+\).*$/\1/'`
   save_IFS=$IFS;IFS='
';    if [ "${anchor##*.}" == tbz2 ];then
         lines=( `tar xfjO $anchor --occurrence=1 --wildcards 'loop.*.s'|$base/get_loop $inner 5 5 -l -s -f -n 0|$base/find_lines|sed 's/^\s*\(\/\)\?\([^\/]\+\/\)*//'` )
      else
         lines=( `cat $anchor|$base/get_loop $inner 5 5 -l -s -f -n 0|$base/find_lines|sed 's/^\s*\(\/\)\?\([^\/]\+\/\)*//'` )
      fi
   IFS=$save_IFS
   disasm=`mktemp`
   $base/get_disasm "$module"${func:+ $func} >$disasm
   vec_flag=false
   loop_seen=false
   while [ $var -ne 1 ];do
      for l in ${lines[@]};do
         cat $disasm|$base/get_loop $l ${line#* } >$target
         var=$(grep -c ';===' $target)
         if [ $var -ne 0 ];then loop_seen=true; fi
         if [ $var -eq 1 ];then
            if [ `$base/find_lines <$target|wc -l` -gt $bloat ] && [ $bloat -ne 0 ];then
               if [ $shown_luqi == false ];then
                  echo
                  echo Warning: Some loops are skipped due to significant
                  echo '         'increase of unique lines. To override, use
                  echo '         'TRACING_SDK_PROPAGATE_LUQI=ratio
                  echo
                  shown_luqi=true
               fi
               var=0
            else
               break 2
            fi
         fi
      done
      relax=`echo $line|sed 's/\s-p\(\s\|$\)/\1/'`
      if [ "$relax" != "$line" ];then
         line=$relax
         cat $disasm|$base/get_loop $line >$target
         var=$(grep -c ';===' $target)
      else
         noidx=`echo $line|sed 's/\s-i\s\+[0-9]\+\(\s\|$\)/\1/'`
         if [ "$noidx" != "$line" ] && [ -z "$TRACING_SDK_PROPAGATE_HIDX" ];then
            line=$noidx' -p'
            cat $disasm|$base/get_loop $line >$target
            var=$(grep -c ';===' $target)
         elif [ $vec_flag == false ] && [ -z "$TRACING_SDK_PROPAGATE_HIDX" ];then
            novec=`echo $line|sed 's/\s-v\s\+[0-9]\+\(\s\|$\)/\1/'`
            if [ "$novec" != "$line" ];then
               line=$novec' -p'
               cat $disasm|$base/get_loop $line >$target
               var=$(grep -c ';===' $target)
               echo Warning: For specified loop version without SIMD instructions chosen.
               echo '         'Specifying TRACING_SDK_PROPAGATE_VFCT=F might be required.
               echo
            else
               line=${line/ -p/}' -p -v 0'
               cat $disasm|$base/get_loop $line >$target
               var=$(grep -c ';===' $target)
               echo Warning: For specified loop version with SIMD instructions chosen.
               echo '         'Specifying TRACING_SDK_PROPAGATE_VFCT=F might be required.
               echo
            fi
            vec_flag=true
         elif [ $loop_seen == false ];then
            nofunc=`echo $line|sed 's/\s-r\s\+\S\+\(\s\|$\)/\1/'`
            if [ "$nofunc" != "$line" ];then
               if [ -n "$TRACING_SDK_PROPAGATE_HIDX" ];then
                  line=`echo $nofunc|sed 's/\(\s-[iv]\s\+[0-9]\+\)\(\s\|$\)/ -p\1\2/'`
               else
                  line=`echo $nofunc|sed 's/\s-[iv]\s\+[0-9]\+\(\s\|$\)/\1/'`' -p'
               fi
               cat $disasm|$base/get_loop $line >$target
               var=$(grep -c ';===' $target)
               vec_flag=false
               loop_seen=true
            else
               break
            fi
         else
            break
         fi
      fi
      if [ $var -eq 1 ] && [ `$base/find_lines <$target|wc -l` -gt $bloat ] && [ $bloat -ne 0 ];then
         if [ $shown_luqi == false ];then
            echo
            echo Warning: Some loops are skipped due to significant
            echo '         'increase of unique lines. To override, use
            echo '         'TRACING_SDK_PROPAGATE_LUQI=ratio
            echo
            shown_luqi=true
         fi
         var=0
      fi
   done
   if [ $var -ne 1 ];then
      echo Error: Corresponding loop can\'t be found automatically.
      if [ $var -ge 2 ];then
         echo '       'Try to regather $(basename $anchor) with TRACING_SDK_FIND_LOOP_NSTS=\"1 2\"
      elif [ $var -eq 0 ];then
         echo '       'Do you have debug info generated\?
      fi
      echo '       'If none of above helps, then exact call graph
      echo '       'based analysis is required.
      echo
      exit
   fi
   rm $disasm
fi

if [ -n "$precond" ];then
   start_cond=$($base/precond print "$precond")' '
fi

shown_sfct=false

if [ "${anchor##*.}" == tbz2 ] || [ -n "$cmdl" ];then
   modes=( current '' strict relaxed circle circle+strict outside error )
   for mode in "${modes[@]}";do
      if [ "$mode" == current ];then
         mode="$TRACING_SDK_GET_RANGES_MODE"
      elif [ "$mode" == "$TRACING_SDK_GET_RANGES_MODE" ];then
         continue
      elif [ "$mode" == error ];then
         echo;echo Error: Trace\'s arguments don\'t correspond to stored start;echo;exit
      fi
      if [ -z "$cmdl" ];then
         org_range=( `tar xfjO $anchor --occurrence=1 --wildcards "$selmsk"|TRACING_SDK_GET_RANGES_MODE="$mode" $base/get_ranges $selrng|head -n 1` )
      else
         org_range=( `cat $anchor|TRACING_SDK_GET_RANGES_MODE="$mode" $base/get_ranges $selrng|head -n 1` )
      fi
      if [ -z "${org_range[4]}" ] && [ -z "${org_range[5]}" ];then
         org_range[4]="${org_range[2]}";org_range[5]="${org_range[2]}";org_range[2]="${org_range[1]}";org_range[3]="${org_range[1]}";org_range[1]="${org_range[0]}"
      fi
      if [ -z "$cmdl" ];then
         eval sde_args=( `tar xfjO $anchor --wildcards 'pinlit64.*[0-9].result' 2>/dev/null|grep -m 1 '^run_sde-command-line:'|sed 's/^run_sde-command-line:\s\+\(.*\s\+-start-address\s\+\)\(0x[0-9a-fA-F]\+\)\(:[0-9]\+\)\?\(.*\s\+-stop-address\s\+\)\(0x[0-9a-fA-F]\+\)\(:[0-9]\+\)\?\(.*\s\+-length\s\+\)\([0-9]\+\)\(\s\+.*\)$/'"'"'\1'"' '"'\2'"' '"'\3'"' '"'\4'"' '"'\5'"' '"'\6'"' '"'\7'"' '"'\8'"' '"'\9'"'"'/'` )
      fi
      re='\s-record\s';if [[ ${sde_args[0]} =~ $re ]];then action=-record; else action=-pinlit2; fi
      sde_args[0]=`echo "${sde_args[0]}"|sed -e 's/^.*-\(pinlit2\|record\|pinlit\)/'"$tgt"' '$action'/' -e 's/\(-waitfor-address\s\+\S\+\s\+\)\+/'"$start_cond"'/'`
      sde_args[8]=`echo "${sde_args[8]}"|sed 's/\s\+-moi\s\+\S\+/ -moi '$(basename "$module")'/'`
      if [ ${sde_args[1]} == "${org_range[1]}" ];then
         skip_loop=false
      elif [ ${sde_args[1]} == "${org_range[0]}" ];then
         skip_loop=true
      else
         continue
      fi
      if [ ${sde_args[4]} == "${org_range[2]}" ];then
         whole_loop=false
      elif [ ${sde_args[4]} == "${org_range[3]}" ];then
         whole_loop=true
      else
         continue
      fi
      break
   done
else
   mode="$TRACING_SDK_GET_RANGES_MODE"
fi

if [ -z "$line" ];then selrng="$func"; fi

len_chk=true;unset len_ovr
if [ -n "$TRACING_SDK_PROPAGATE_LEN" ];then
   len_opt="${TRACING_SDK_PROPAGATE_LEN#*+}"
   if [ "$len_opt" == nocheck ];then
      len_chk=false
      if [ "$len_opt" != "$TRACING_SDK_PROPAGATE_LEN" ];then
         len_ovr="${TRACING_SDK_PROPAGATE_LEN%%+*}"
      fi
   else
      len_ovr="$TRACING_SDK_PROPAGATE_LEN"
   fi
   len_ovr=${len_ovr//B/000000000};len_ovr=${len_ovr//M/000000};len_ovr=${len_ovr//K/000}
fi

save_IFS="$IFS";IFS='
';ranges=( `TRACING_SDK_GET_RANGES_MODE="$mode" $base/get_ranges $selrng <$target` );IFS="$save_IFS"

for r in "${ranges[@]}";do
   tgt_range=( $r )
   if [ "${anchor##*.}" == tbz2 ] || [ -n "$cmdl" ];then
      if [ -z "${tgt_range[4]}" ] && [ -z "${tgt_range[5]}" ];then
         tgt_range[4]=${tgt_range[2]};tgt_range[5]=${tgt_range[2]};tgt_range[2]=${tgt_range[1]};tgt_range[3]=${tgt_range[1]};tgt_range[1]=${tgt_range[0]}
      fi
      if [ $skip_loop != true ];then
         tgt_start=${tgt_range[1]}
      else
         tgt_start=${tgt_range[0]}
      fi
      if [ $whole_loop != true ];then
         tgt_stop=${tgt_range[2]}
         stop_scnt_adj=${tgt_range[4]}
         stop_scnt_ofs=`echo "${org_range[4]}-$stop_scnt_adj"|bc`
         if [ -n "$line" ] && [[ $line == *' -n 0'* ]];then
            echo
            echo Warning: The loop has been traced in iterations mode.
            echo '         'Specifying TRACING_SDK_PROPAGATE_VFCT=F might be required.
            echo
         fi
      else
         tgt_stop=${tgt_range[3]}
         stop_scnt_adj=${tgt_range[5]}
         stop_scnt_ofs=`echo "${org_range[5]}-$stop_scnt_adj"|bc`
      fi
      start_scnt=${sde_args[2]#:};if [ "$start_scnt" == "${sde_args[2]}" ];then start_scnt=1; fi
      org_stop_scnt="${sde_args[5]}"
      stop_scnt=${org_stop_scnt#:};if [ "$stop_scnt" == "$org_stop_scnt" ];then stop_scnt=1; fi
      if [ $stop_scnt_ofs != '0' ];then
         stop_scnt=`echo "$stop_scnt-($stop_scnt_ofs)"|bc`
         if [ $stop_scnt -lt 1 ];then stop_scnt=1; fi
         sde_args[5]=":$stop_scnt"
      fi
      org_cmd=${sde_args[0]}$tgt_start${sde_args[2]}${sde_args[3]}$tgt_stop${sde_args[5]}${sde_args[6]}${sde_args[7]}${sde_args[8]}
      if [ $iters_rqrd == true ];then
         if [ $skip_loop == true ];then
            tgt_start=${tgt_range[1]}
         else
            tgt_start=${tgt_range[0]}
         fi
         if [ $whole_loop == true ];then
            tgt_stop=${tgt_range[2]}
            stop_scnt_adj=${tgt_range[4]}
            stop_scnt_ofs=`echo "${org_range[4]}-($stop_scnt_adj)"|bc`
         else
            tgt_stop=${tgt_range[3]}
            stop_scnt_adj=${tgt_range[5]}
            stop_scnt_ofs=`echo "${org_range[5]}-($stop_scnt_adj)"|bc`
            echo
            echo Error: To use TRACING_SDK_PROPAGATE_VFCT=full nesting level of the base trace
            echo '       'should be at least 1 or hotspot traced in loops mode.
            echo
            break
         fi
         stop_scnt=${org_stop_scnt#:};if [ "$stop_scnt" == "$org_stop_scnt" ];then stop_scnt=1; fi
         if [ $stop_scnt_ofs == '0' ];then
            sde_args[5]="$org_stop_scnt"
         else
            stop_scnt=`echo "$stop_scnt-($stop_scnt_ofs)"|bc`
            if [ $stop_scnt -lt 1 ];then stop_scnt=1; fi
            sde_args[5]=":$stop_scnt"
         fi
      fi
      if [ -n "$TRACING_SDK_PROPAGATE_OFS" ];then
         start_scnt=`echo "t=$start_scnt+(0$TRACING_SDK_PROPAGATE_OFS);if(t<=1)1 else t"|bc`
         sde_args[2]=":$start_scnt"
      fi
      if [ -n "$TRACING_SDK_PROPAGATE_VFCT" ] && [ $TRACING_SDK_PROPAGATE_VFCT != full ] && [ $TRACING_SDK_PROPAGATE_VFCT != conflict ];then
         if [ $skip_loop  == false ];then prg_fct="$TRACING_SDK_PROPAGATE_VFCT"; fi
         if [ $whole_loop == false ];then epg_fct="$TRACING_SDK_PROPAGATE_VFCT"; fi
      fi
      if [ -n "$TRACING_SDK_PROPAGATE_BFCT" ];then
         if [ $skip_loop  == true ];then prg_fct="$TRACING_SDK_PROPAGATE_BFCT"; fi
         if [ $whole_loop == true ];then epg_fct="$TRACING_SDK_PROPAGATE_BFCT"; fi
      fi
      if [ -n "$TRACING_SDK_PROPAGATE_SCL"  ];then epg_fct="1/($TRACING_SDK_PROPAGATE_SCL)";len_fct="$epg_fct"; fi
      if [ -n "$TRACING_SDK_PROPAGATE_TFCT" ];then len_fct="$TRACING_SDK_PROPAGATE_TFCT"; fi
      if [ -n "$TRACING_SDK_PROPAGATE_PFCT" ];then prg_fct="$TRACING_SDK_PROPAGATE_PFCT"; fi
      if [ -n "$TRACING_SDK_PROPAGATE_EFCT" ];then epg_fct="$TRACING_SDK_PROPAGATE_EFCT"; fi
      if [ -n "$prg_fct" ];then
         start_scnt=`echo "scale=20;f=($prg_fct);scale=0;c=$start_scnt/f;if(c<1)1 else c"|bc`
         if [ $start_scnt == "1" ];then sde_args[2]=''; else sde_args[2]=":$start_scnt"; fi
      fi
      if [ -n "$epg_fct" ];then
         stop_scnt=`echo "scale=20;f=($epg_fct);scale=0;c=($stop_scnt-($stop_scnt_adj))/f;if(c<1)c=1;c+=($stop_scnt_adj);if(c<1)1 else c"|bc`
         if [ $stop_scnt == "1" ];then sde_args[5]=''; else sde_args[5]=":$stop_scnt"; fi
      fi
      tgt_len=${sde_args[7]}
      if [ -n "$len_fct" ];then
         tgt_len=`echo "scale=20;f=($len_fct);scale=0;c=$tgt_len/f;if(c<1)1 else c"|bc`
      fi
      if [ -n "$len_ovr" ];then tgt_len="$len_ovr"; fi
      sde_args[7]=$tgt_len
      tid=`echo $org_cmd|grep '\-tid'|sed 's/^.*\s\+-tid\s\+\([0-9]\+\).*$/\1/'`
      idx=${tid:-0}
      mt_mode=`echo $org_cmd|sed -n 's/^.*\(\s-mt\)\(\s\|$\).*$/\1/p'`
      if [ -z "$mt_mode" ];then rdx=0; else rdx=$idx; fi
      if [ -n "$prior" ];then
         tgt_size=`tar xfjO $anchor --wildcards 'pinlit64.'$idx'.result' 2>/dev/null|grep -m 1 '^inscount:'|awk '{print $2}'`
         if [ -n "$TRACING_SDK_PROPAGATE_TFCT" ];then
            tgt_size=`echo scale=20\;factor=$TRACING_SDK_PROPAGATE_TFCT\;scale=0\;"$tgt_size"/factor/1|bc`
         fi
         skip_step="$tgt_len"
         miss_cnt=1
         empty_cnt=1
         flct=100000
         fst_skip=''
         fst_comp=''
      fi
      cmd=${sde_args[0]}$tgt_start${sde_args[2]}${sde_args[3]}$tgt_stop${sde_args[5]}${sde_args[6]}${sde_args[7]}${sde_args[8]}$extra
      if [ $# -gt 3 ];then
         shift 3
         unset ofss
         ofs=''
         skip=''
         comm=`mktemp $PWD/comm.XXXXXXXXXX`
         while [ 1 ];do
            if [ -n "$TRACING_SDK_PROPAGATE_EXTRA" ];then
               if [ -z "$ofs" ];then
                  r="$tgt -icount $start_cond-stop-address $tgt_start${sde_args[2]}${sde_args[8]}$mt_mode$extra"
               else
                  if [ -z "$skip" ];then
                     if [ $ofs -ge $prior ];then
                        skip=$(( ofs - prior ))
                        if [ $skip -ge $((flct+skip_step*empty_cnt)) ];then 
                           (( skip -= flct+skip_step*empty_cnt ))
                        elif [ $skip -ge $((flct+skip_step)) ];then 
                           (( skip -= flct+skip_step ))
                        else
                           skip=0
                        fi
                        comp=$((ofs-prior-skip ))
                        if [ $comp -ge $flct ];then (( comp -= flct )); else comp=0; fi
                        if [ -z "$fst_skip" ];then 
                           fst_skip=$skip
                           fst_comp=$comp
                        fi
                        if [ -n "$TRACING_SDK_PROPAGATE_SFCT" ];then
                           skip=`echo "scale=20;factor=$TRACING_SDK_PROPAGATE_SFCT;scale=0;$skip/factor"|bc`
                        fi
                        wnd_len=$((prior+skip_step*empty_cnt+flct+tgt_len))
                     else
                        echo
                        echo Error: Extra size \($TRACING_SDK_PROPAGATE_EXTRA\) is greater than offset to hot spot \($ofs\)
                        echo '       'Reduce TRACING_SDK_PROPAGATE_EXTRA or increase TRACING_SDK_GATHER_SCNT by ~`echo "scale=1;t=$prior/$ofs;if(t<1.1) 1.1 else t"|bc`X
                        echo
                        break 2
                     fi
                  fi
                  r=`echo $cmd|sed -e 's/\(-waitfor-address\s\+\S\+\s\+\)\?-start-address\s\+\(0x[0-9a-fA-F]\+\)\(:[0-9]\+\)\?/-skip '$skip'/' -e 's/-stop-address\s\+\(0x[0-9a-fA-F]\+\)\(:[0-9]\+\)\?\s*//' -e 's/-length\s\+[0-9]\+/-length '$wnd_len'/'`
               fi
            else
               r="$cmd"
            fi
            if [ $log_type == pinball ];then r=${r/$action/-record}; fi
            TRACING_SDK_SDE_MPI_ARGS="$r -comm-channel $comm"${global:+ $global} "$@"
###            echo $PWD >$comm
            dir=( `tail -n 1 $comm` )
            if [ -z "$dir" ];then
               echo;echo Error: Communication channel is broken;echo;break 2
            fi
            if [ -n "$prior" ] && [ -z "$ofs" ];then
               size=`grep '$$ TID: '$idx' ICOUNT:' -i $dir/sde-icount.txt|awk 'END{print $NF}'`
               if [ -z "$size" ];then echo;echo Error: ICOUNT broken;echo;break 2; fi
               ofss[${#ofss[@]}]=$size
               ofs=0
               for o in "${ofss[@]}";do
                  ofs=`echo $ofs + $o|bc`
               done
               ofs=`echo $ofs / "${#ofss[@]}"|bc`
               continue
            fi
            pinball=$dir/rgn.pinball
            if [ ! -d $pinball ];then
               echo;echo Error: Application didn\'t run;echo;break 2
            fi
            result=`find "$pinball" \( -name '*.'$idx'.result' -o -name '*.global.log' \) -exec grep -m 1 -q '\-control\|-replay' {} \; \! -exec grep -m 1 -q '^inscount: 18446744073709551615$' {} \; \! -exec grep -m 1 -q '^num_threads_started: 0$' {} \; -print|tail -n 1|sed 's/\(\.[0-9]\+\)\?\.global\.log$/.'$idx'.result/'`
            if [ -z "$result" ];then
               echo;echo Error: Region of interest hasn\'t been reached;echo;break 2
            fi
            rm -rf "$dir/rgn.itrace";mv $(dirname "$result") "$dir/rgn.itrace";rm -rf "$pinball" "$dir/.mptrace"
            result="$dir/rgn.itrace/"$(basename "$result")
            size=`grep -m 1 -w inscount $result|awk '{print $2}'`
            if [ -z "$size" ];then
               echo;echo Error: Propagation failed \(see pintool.log for details\);echo;break 2
            fi
            basename=${result%.result};if [ ! -f $basename.arch.xml ] && [ ! -f $basename.address ];then basename=${basename%.*[0-9]}; fi
            if [ `grep -c '0x0\+\s' $basename.address` -ne 0 ];then
               echo;echo Warning: Detecting zero address access, trying to recover...;echo
               sed '/0x0\+\s/d' $basename.address >$basename.fix.address
               mv -f $basename.fix.address $basename.address
            fi
            if [ -n "$TRACING_SDK_PROPAGATE_EXTRA" ];then
               if [ $size -le $((prior+tgt_size+flct)) ];then
                  if [ $shown_sfct == false ];then
                     echo
                     echo   Warning: Application terminated before end of region reached
                     echo '         'You might want to use TRACING_SDK_PROPAGATE_SFCT=F
                     echo
                     shown_sfct=true
                  fi
                  delta=$((miss_cnt*(prior+tgt_len+flct-size)+tgt_len))
                  (( miss_cnt++ ))
                  if [ $skip -ge $delta ];then
                     (( skip -= delta ))
                  elif [ $skip -gt 0 ];then
                     skip=0
                  else
                     echo;echo Error: Interim trace can\'t be collected;echo;break 2
                  fi
                  continue
               fi
               max_right=$((size-prior))
               left=''
               prob=0
               size=$tgt_len
               step_left=$((tgt_size/3))
               eps_cnt=100
               min_prob=$((eps_cnt+1))
               step_prob=$min_prob
               tgt_err=0.1
               adjt_avlb=false
               size_avlb=false
               init_comp=$comp
               trc_strt_scnt=''
               trc_stop_scnt="${sde_args[5]}"
               if [ $empty_cnt -gt 1 ];then comp=0;init_comp=0; fi
               #if [ $tgt_start == $tgt_stop ] && [ -n "$trc_stop_scnt" ];then trc_stop_scnt=${trc_stop_scnt#:};trc_stop_scnt=":$((trc_stop_scnt-1))"; fi

               stream="$(dirname "$result")"/stream.txt
               range=( `echo $tgt_start $tgt_stop|sed 's/\(^\|\s\+\)\(0x\)\?0*\([[:xdigit:]]\+\)/\1\3/g'` 1 )
               if [ -n "${sde_args[5]}" ];then range[2]=${sde_args[5]#:}; fi
               $base/flt_sde -itrace-file "^TID$rdx:" $tgt -pinlit2-replay64 $basename -itrace-execute -itrace-disasm 0 -tid $rdx -skip $prior|cat -n|grep -i "\s\(${range[0]:-NA}\|${range[1]:-NA}\)\$" >"$stream" #|sed '/^\s\+1\s/d' >"$stream" # workaround for SDE 8.3
               rec=( `$base/get_icount $tgt_size ${range[0]} ${range[1]} ${range[2]} <"$stream"` )
               if [ -n "${rec[1]}" ];then
                  comp="${rec[1]}"
                  init_comp=0
                  adjt=$comp;adjt_avlb=true
                  size="${rec[2]}";size_avlb=true
                  trc_strt_scnt="${rec[0]}"
               fi

               prv_left=$max_right
               prv_size=0
               while [ 1 ];do
                  move_left=''
                  if [ $adjt_avlb == true ];then
                     adjt_avlb=false
                  else
                     adjt=`$base/run_sde $tgt -pinlit2-replay64 $basename -icount -tid $rdx -skip $((prior+comp+prob)) -stop-address $tgt_start 2>&1|grep '$$ TID: '$rdx' ICOUNT:' -i|awk 'END{print $NF}'`
                     if [ -z "$adjt" ];then
                        echo;echo Error: Interim trace can\'t be replayed;echo;break 3
                     fi
                     if [ $empty_cnt -gt 1 ];then
                        comp=$init_comp
                        if [ $((adjt+tgt_size)) -ge $((max_right-eps_cnt)) ];then
                           size=$tgt_len
                           break
                        else
                           empty_cnt=1
                           if [ $adjt -ge $comp ];then
                              (( adjt -= comp ))
                           else
                              continue
                           fi
                        fi
                     fi
                     if [ $prob -gt 0 ] && [ $adjt -lt $((step_left/512)) ];then
                        if [ $step_prob == $min_prob ];then
                           step_prob=$((step_left/4096))
                           if [ $step_prob -le $min_prob ];then step_prob=$((min_prob*2)); fi
                        else
                           (( step_prob *= 2 ))
                           if [ $step_prob -gt $step_left ];then step_prob=$step_left; fi
                        fi
                     else
                        step_prob=$min_prob
                     fi
                     adjt=$((comp+prob+adjt))
                     if [ $prob -eq 0 ];then left=$adjt; fi
                     if [ $adjt -ge $((prv_left-eps_cnt)) ];then
                        move_left=`echo "$comp-$step_left"|bc`
                     elif [ $((adjt+tgt_size)) -ge $((max_right-eps_cnt)) ];then
                        move_left=`echo "$comp-$step_left"|bc`
                     else
                        skip_err=`$base/run_sde $tgt -pinlit2-replay64 $basename -icount -tid $rdx -length $((prior+adjt)) 2>&1|grep '$$ TID: '$rdx' ICOUNT:' -i|awk 'END{print $NF}'`
                        if [ -z "$skip_err" ];then
                           echo;echo Error: Interim trace can\'t be replayed;echo;break 3
                        fi
                        adjt=`echo "t=$skip_err-$prior;if(t<0)0 else t"|bc`
                        adjt_err=`$base/run_sde $tgt -pinlit2-replay64 $basename -icount -tid $rdx -skip $((prior+adjt)) -stop-address $tgt_start 2>&1|grep '$$ TID: '$rdx' ICOUNT:' -i|awk 'END{print $NF}'`
                        if [ -z "$adjt_err" ];then
                           echo;echo Error: Interim trace can\'t be replayed;echo;break 3
                        fi
                        adjt=$((adjt+adjt_err))
                     fi
                  fi
                  if [ -z "$move_left" ];then
                     if [ $prob -eq 0 ];then left=$adjt; fi
                     if [ $adjt -ge $((prv_left-eps_cnt)) ];then
                        move_left=`echo "$comp-$step_left"|bc`
                     elif [ $((adjt+tgt_size)) -ge $((max_right-eps_cnt)) ];then
                        move_left=`echo "$comp-$step_left"|bc`
                     else
                        if [ $size_avlb == true ];then
                           size_avlb=false
                        else
                           size=`$base/run_sde $tgt -pinlit2-replay64 $basename -icount -tid $rdx -skip $((prior+adjt)) -stop-address $tgt_stop$trc_stop_scnt 2>&1|grep '$$ TID: '$rdx' ICOUNT:' -i|awk 'END{print $NF}'`
                           if [ -z "$size" ];then
                              echo;echo Error: Interim trace can\'t be replayed;echo;break 3
                           fi
                        fi
                        if [ `echo "t=$tgt_size-$size;if(t<0)t=-t;scale=20;t/=0.5*($tgt_size+$size);t>=$tgt_err"|bc` -eq 1 ];then
                           if [ -n "$TRACING_SDK_PROPAGATE_TRLX" ];then
                              if [ `echo "t=$prv_size-$size;if(t<0)t=-t;scale=20;t/=0.5*($prv_size+$size);t<$tgt_err"|bc` -eq 1 ];then
                                 tgt_err=`echo "scale=20;$tgt_err+$TRACING_SDK_PROPAGATE_TRLX"|bc`
                              else
                                 tgt_err=0.1   
                              fi
                           fi
                           if [ $comp -eq $init_comp ] && [ $init_comp -ne 0 ];then
                              move_left=`echo "$comp-$step_left"|bc`
                           elif [ $((adjt+size)) -ge $((max_right-eps_cnt)) ];then
                              move_left=`echo "$comp-$step_left"|bc`
                           else
                              move_left=`echo "$adjt+$step_prob"|bc`
                           fi
                        else
                           if [ `echo "$tgt_len<$size"|bc` -eq 1 ];then tgt_len=`echo "$size+2*$eps_cnt"|bc`; fi
                        fi
                        prv_size=$size
                     fi
                  fi
                  new_comp=''
                  if [ -n "$move_left" ];then
                     if [ `echo "$move_left>=$prv_left-$eps_cnt"|bc` -eq 1 ];then
                        new_comp=`echo "$comp-$step_left"|bc`
                     elif [ `echo "$move_left<$comp-$eps_cnt"|bc` -eq 1 ];then
                        new_comp=$move_left
                     else
                        prob=`echo "$move_left-$comp"|bc`
                        continue
                     fi
                  fi
                  if [ -n "$new_comp" ];then
                     if [ `echo "$new_comp<=0"|bc` -eq 1 ];then
                        if [ $comp -eq 0 ];then
                           size=$tgt_len
                           break
                        else
                           new_comp=0
                        fi
                     fi
                     comp=$new_comp
                     prob=0
                     prv_left=$left
                     continue
                  fi
                  break
               done
               max_size=`echo "$tgt_len-$eps_cnt"|bc`
            else
               max_size=`echo "$tgt_len * 98 / 100"|bc`
            fi
            if [ $size -gt $max_size ];then
               if [ -n "$skip" ];then
                  miss_cnt=1
                  (( empty_cnt++ ));if [ $empty_cnt -gt 10 ];then empty_cnt=10; fi
                  if [ $((ofs+init_comp)) -gt $((prior+max_right)) ];then
                     ofs=$((ofs+init_comp-max_right))
                  elif [ $ofs -ge $((prior+skip_step)) ];then
                     (( ofs -= skip_step ))
                  elif [ $skip -gt $prior ];then
                     ofs=$prior
                  else
                     echo;echo Error: Interim trace can\'t be collected;echo;break 2
                  fi
                  skip=''
                  continue
               fi
               if [ $len_chk != false ];then
                  echo;echo Error: Number of instructions in trace greater than limit;echo;break 2
               fi
            elif [ $size -lt 100000 ];then
               if [ -n "$skip" ];then
                  ofs='';skip=''
                  continue
               fi
               echo;echo Warning: Low number of instructions in trace \($size\);echo
            fi
            if [ -n "$skip" ] && [ -n "$fst_skip" ];then
               echo;echo Remark: To speed-up process use TRACING_SDK_PROPAGATE_SFCT=`echo "scale=5;$fst_skip/($skip+$adjt-$fst_comp)"|bc|sed 's/^\./0./'` next time.;echo
            fi
            break
         done
         if [ "${TRACING_SDK_STRACE_TYPE:0:3}" == mid ] || ( [ $log_type != pinball ] && [ $action != -record ] );then
            sdir=$(dirname "$result")
         elif [ $log_type == pinball ] && [ $action == -record ];then
            sdir=$(dirname "$result")
            rename "$basename" "$sdir/pinlit64" "$basename"*
            basename=$(basename "$basename")
            result=$(basename "$result")
            basename="$sdir/${basename/#record/pinlit64}"
            result="$sdir/${result/#record/pinlit64}"
         else
            sdir=$dir/rgn.strace
            $base/run_sde $tgt -pinlit2-replay64 "$basename" $action -tid $rdx$mt_mode -log:basename "$sdir/pinlit64"
            basename="$sdir/pinlit64"
            [ $rdx -eq $idx ] || rename $basename.$rdx $basename.$idx $basename.$rdx.*
            result=$basename.$idx.result
            if [ ! -f $basename.arch.xml ] && [ ! -f $basename.address ];then basename=$basename.$idx; fi
         fi
         if [ -n "$TRACING_SDK_PROPAGATE_SCL" ];then
            if [ `echo "scale=20;($TRACING_SDK_PROPAGATE_SCL)>1"|bc` -eq 1 ];then
               $base/run_sde $tgt -pinlit2-replay64 $basename -mix -tid $rdx$mt_mode -omix $sdir/mix-out.sw.txt -stop-address $tgt_stop:$((stop_scnt-stop_scnt_adj))
               $base/coverage $basename.procinfo.xml <$sdir/mix-out.sw.txt >$sdir/coverage.sw.txt
               org_size=`$base/coverage -tid $rdx <$sdir/mix-out.sw.txt`
            else
               unset org_size
            fi
            if [ -z "$org_size" ] || [ $org_size -eq 0 ];then
               scale=$TRACING_SDK_PROPAGATE_SCL
            else
               scale=`echo scale=3\;$size/$org_size|bc`
            fi
         fi
         if [ -n "$TRACING_SDK_PROPAGATE_EXTRA" ];then
            if [ -n "$trc_strt_scnt" ];then
               prolog="$prior+$tgt_start"
               if [ $trc_strt_scnt != 1 ];then prolog="$prolog:$trc_strt_scnt"; fi
            else
               prolog=$((prior+adjt))
            fi
            #hotspot=$size
         fi
         trace=`readlink -f $anchor|sed 's/\.\(SSE4\.\|AVX\|FMA\|AVX3\.\|LRB\|SMADD\)[0-9]*\(\.[^\/]*\)\?\.tbz2$/.'$sfx'/'`
         strace=$(basename $trace);strace="${strace#lit.}";strace="${strace#log.}"
         if [ "${TRACING_SDK_STRACE_TYPE:0:3}" == mid ] && [ `readlink -f $anchor` == $trace.tbz2 ];then
            tar xfjO $anchor --occurrence=1 distrib.txt 2>/dev/null >$sdir/distrib.txt
            [ -s $sdir/distrib.txt ] || rm -f $sdir/distrib.txt
         fi
         if [ ! -f $sdir/distrib.txt ];then
            tar xfjO $anchor --occurrence=1 baseline.txt 2>/dev/null >$sdir/baseline.txt
            [ -s $sdir/baseline.txt ] || tar xfjO $anchor --occurrence=1 coverage.sw.txt 2>/dev/null >$sdir/baseline.txt
            [ -s $sdir/baseline.txt ] || tar xfjO $anchor --occurrence=1 coverage.txt 2>/dev/null >$sdir/baseline.txt
            [ -s $sdir/baseline.txt ] || rm -f $sdir/baseline.txt
            tar xfjO $anchor --occurrence=1 groups.bl.txt 2>/dev/null >$sdir/groups.bl.txt
            [ -s $sdir/groups.bl.txt ] || tar xfjO $anchor --occurrence=1 groups.sw.txt 2>/dev/null >$sdir/groups.bl.txt
            [ -s $sdir/groups.bl.txt ] || tar xfjO $anchor --occurrence=1 groups.txt 2>/dev/null >$sdir/groups.bl.txt
            [ -s $sdir/groups.bl.txt ] || rm -f $sdir/groups.bl.txt
         fi
         tar xfj $anchor --occurrence=1 profile.csv 2>/dev/null
         [ -s profile.csv ] || [ $(dirname $anchor) == '.' ] || [ ! -s $(dirname $trace)/profile.csv ] || cp -u $(dirname $trace)/profile.csv .
         if [ "${TRACING_SDK_STRACE_TYPE:0:3}" == mid ];then
            tar xfjO $anchor --occurrence=1 coverage.sw.txt 2>/dev/null >$sdir/coverage.sw.txt
            [ -s $sdir/coverage.sw.txt ] || tar xfjO $anchor --occurrence=1 coverage.txt 2>/dev/null >$sdir/coverage.sw.txt
            [ -s $sdir/coverage.sw.txt ] || rm -f $sdir/coverage.sw.txt
            tar xfjO $anchor --occurrence=1 groups.sw.txt 2>/dev/null >$sdir/groups.sw.txt
            [ -s $sdir/groups.sw.txt ] || tar xfjO $anchor --occurrence=1 groups.txt 2>/dev/null >$sdir/groups.sw.txt
            [ -s $sdir/groups.sw.txt ] || rm -f $sdir/groups.sw.txt
            [ -f $sdir/../environment.txt ] && mv -fu $sdir/../environment.txt $sdir/environment.txt
            [ -f profile.csv ] && cp -u profile.csv $sdir/profile.csv
            cp $target $sdir
            [ -n "$precond" ] && cp -u "$precond" $sdir
            deps=`sed -n 's/^;\s\+dependencies:\s\+\(.\+\)/\1/p' $target|xargs echo`
            [ -n "$deps" ] && cp -u $deps $sdir
            echo >>$result
            [ -z "$prolog" ] || echo "prolog: $prolog" >> $result
            [ -z "$hotspot" ] || echo "hotspot: $hotspot" >> $result
            echo "run_sde-command-line: $cmd" >>$result
            strace=$(dirname $trace)/"mid.$strace";rm -rf $strace;mv $sdir $strace
         else
            TRACING_SDK_STRACE="$sdir" TRACING_SDK_STRACE_TYPE="$TRACING_SDK_STRACE_TYPE" TRACING_SDK_SDE_MPI_ARGS="$cmd" action="$action" scale="$scale" tid="$tid" size="$size" precond="$precond" $base/gather
            strace=$(dirname $trace)/"rgn.$strace";rm -rf $strace;mv $sdir $strace
            if [ "$action" == -record ];then
               cur=$PWD;cd $strace;tar cfvj $trace.tbz2 *;cd $cur
            else
               precnd=$strace/precond.$isa.tbz2;if [ -r "$precnd" ];then precnd=$(basename $precnd); else unset precnd; fi
               deps=`sed -n 's/^;\s\+dependencies:\s\+\(.\+\)/\1/p' "$target"|xargs echo`
               cur=$PWD;cd $strace;$base/pack_trace $trace $target${precnd:+ $precnd}${deps:+ $deps};cd $cur
            fi
         fi
         rm $comm
      else
         echo;echo '   sde '$cmd' -- $@';echo
      fi
   else
      echo
      echo Use the following command if the first command suggested by find_loop was used:
      echo
      echo '   'sde ${tgt:+$tgt }-pinlit -trace-mt -start-address ${tgt_range[1]} -stop-address ${tgt_range[3]} -length 100000000 ${extra:+$extra }-moi $(basename "$module") -- '$@'
      echo
      echo Otherwise use the following command with the same skip count for -stop-address:
      echo
      echo '   'sde ${tgt:+$tgt }-pinlit -trace-mt -start-address ${tgt_range[1]} -stop-address ${tgt_range[2]}:1 -length 100000000 ${extra:+$extra }-moi $(basename "$module") -- '$@'
      echo
   fi
   break
done
